#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cerrno>
#include <cstring>

#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
using namespace std;

int main(int argc,char* argv[]) {
    if(argc<=1){
        cout<<"Please input server port for listening."<<endl;
        cout<<"For example ./server 8080"<<endl;
        return 0;
    }
    // socket
    int listenfd = socket(AF_INET, SOCK_STREAM, 0);
    if (listenfd == -1) {
        cout << "Error: socket" << endl;
        return 0;
    }
    // bind绑定地址和端口
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(atoi(argv[1])); //htons是将小端数字转为大端数字，网络接受的是大段数字
    addr.sin_addr.s_addr = INADDR_ANY; //允许所有地址连接
    if (bind(listenfd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
        cout << "Error: bind" << endl;
        return 0;
    }

    // listen监听，第一个参数是socket文件描述符，第二个参数是可以排队的最大连接数
    if(listen(listenfd, 5) == -1) {
        cout << "Error: listen" << endl;
        return 0;
    }
    // accept
    int conn;
    char clientIP[INET_ADDRSTRLEN] = "";
    struct sockaddr_in clientAddr;
    socklen_t clientAddrLen = sizeof(clientAddr);
    bool sustain=true;
    while (sustain) {
        cout << "...listening" << endl;
        conn = accept(listenfd, (struct sockaddr*)&clientAddr, &clientAddrLen);
        if (conn < 0) {
            cout << "Error: accept" << endl;
            continue;
        }
        inet_ntop(AF_INET, &clientAddr.sin_addr, clientIP, INET_ADDRSTRLEN);
        cout << "...connect " << clientIP << ":" << ntohs(clientAddr.sin_port) << endl;

        char buf[255];
        while (true) {
            memset(buf, 0, sizeof(buf));
            int len = recv(conn, buf, sizeof(buf), 0);
            buf[len] = '\0';
            if (strcmp(buf, "exit") == 0) {
                cout << "...disconnect " << clientIP << ":" << ntohs(clientAddr.sin_port) << endl;
                cout<<"Whether to continue listening(y/n).."<<endl;
                char yornl;
                cin>>yornl;
                if(yornl!='y') sustain=false;
                break;
            }
            cout << buf << endl;

            sprintf(buf,"Server accept %d bytes!",len);
            send(conn, buf, strlen(buf), 0);
        }
        
        close(conn);
    }
    close(listenfd);
    return 0;
}